//=============================================================================//
//  ___  ___   _   _   _    __   _   ___ ___ __ __
// |_ _|| __| / \ | \_/ |  / _| / \ | o \ o \\ V /
//  | | | _| | o || \_/ | ( |_n| o ||   /   / \ / 
//  |_| |___||_n_||_| |_|  \__/|_n_||_|\\_|\\ |_|  2006
//										 
//=============================================================================//
/*
Following mess is a hack for getting ATL working under VCEE
*/
#define _ATL_APARTMENT_THREADED
#include <atlbase.h>
extern CComModule _Module;
#include <atlcom.h>

namespace ATL {
    void * __stdcall __AllocStdCallThunk()
    {
        return HeapAlloc(GetProcessHeap(),
            0, sizeof(_stdcallthunk));
    }

    void __stdcall __FreeStdCallThunk(void *p)
    {
        HeapFree(GetProcessHeap(), 0, p);
    }
}
/*
End of mess
*/

#include <locale>
#include <windows.h>
#include <sapi.h>
#include "common/GMLuaModule.h"

ISpVoice* Voice = NULL;
static void Precache(void* param);

GMOD_MODULE( Init, Shutdown );

//gspeak.Say(msg, volume (0~100), rate (-10~10))
LUA_FUNCTION( Say )
{
	const char* msg = g_Lua->GetString(1);
	size_t len = strlen(msg);
	std::locale loc;

	int args = g_Lua->Top();
	long oldRate;
	USHORT oldVolume;

	if(args > 1)
	{
		USHORT volume = (USHORT)g_Lua->GetNumber(2);
		Voice->GetVolume(&oldVolume);
		Voice->SetVolume(volume);
		
		if(args > 2)
		{
			long rate = (long)g_Lua->GetNumber(3);
			Voice->GetRate(&oldRate);
			Voice->SetRate(rate);
		}
	}

	wchar_t* widemsg = (wchar_t*)malloc(sizeof(wchar_t) * len);

	std::use_facet< std::ctype<wchar_t> >(loc).widen ( msg, msg+len, widemsg );
	
	Voice->Speak(widemsg, 0, NULL);

	free(widemsg);

	if(args > 1)
	{
		Voice->SetVolume(oldVolume);
		if(args > 2)
			Voice->SetRate(oldRate);
	}
		
	return 0;
}

int Init( void )
{
	if (FAILED(::CoInitialize(NULL)))
        return 1;

	HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&Voice);
    if( !SUCCEEDED( hr ) )
        return 1;
	
	g_Lua->NewGlobalTable( "gspeak" );
	ILuaObject* table = g_Lua->GetGlobal( "gspeak" );
		table->SetMember( "Say", Say );
	SAFE_UNREF( table );

	CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&Precache, NULL, 0, NULL);

	return 0;
}

static void Precache(void* param)
{
	Voice->Speak(L"G speak loaded!", 0, NULL);
}

//Shut down SAPI
int Shutdown( void )
{
	Voice->Release();
    Voice = NULL;

	::CoUninitialize();
	return 0;
}

